<template>
  <el-dialog
    v-model="dialogVisible"
    title="安全验证"
    width="420px"
    :show-close="false"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    class="verify-dialog"
  >
    <div class="verify-container">
      <div class="verify-header">
        <div class="verify-title">
          <span class="title-icon">
            <el-icon><Lock /></el-icon>
          </span>
          <span class="title-text">请完成人机验证</span>
        </div>
        <p class="verify-desc">拖动下方滑块完成拼图</p>
      </div>

      <div class="verify-puzzle" ref="puzzleEl">
        <!-- 生成的图案背景 -->
        <div class="puzzle-bg" ref="puzzleBg">
          <div class="puzzle-pattern" :style="{ background: bgPatternStyle }"></div>
          <!-- 缺口轮廓 -->
          <div 
            class="puzzle-gap"
            :style="{ left: `${gapLeft}px`, top: `${gapTop}px` }"
          ></div>
        </div>
        
        <!-- 滑块拼图 -->
        <div 
          class="puzzle-piece"
          :class="{ 'active': isDragging, 'success': isSuccess, 'fail': isFailed }"
          :style="{ 
            left: `${pieceLeft}px`, 
            top: `${gapTop}px`
          }"
        >
          <div class="piece-content" :style="{ background: piecePatternStyle }"></div>
        </div>
        
        <!-- 结果指示 -->
        <div class="verify-result" v-if="isSuccess || isFailed">
          <div class="result-icon" :class="{ 'success': isSuccess, 'fail': isFailed }">
            <el-icon v-if="isSuccess"><CircleCheck /></el-icon>
            <el-icon v-if="isFailed"><Warning /></el-icon>
          </div>
          <div class="result-text" :class="{ 'success': isSuccess, 'fail': isFailed }">
            {{ isSuccess ? '验证成功' : '验证失败，请重试' }}
          </div>
        </div>
      </div>
      
      <!-- 滑动条 -->
      <div class="verify-slider">
        <div class="slider-track">
          <div class="slider-track-inner" :style="{ width: `${sliderWidth}px` }"></div>
        </div>
        <div 
          class="slider-button"
          :class="{
            'active': isDragging,
            'success': isSuccess,
            'fail': isFailed
          }"
          ref="sliderBtn"
          @mousedown="handleSliderDown"
          @touchstart="handleSliderDown"
          :style="{ left: `${sliderWidth}px` }"
        >
          <el-icon class="slider-icon" v-if="!isDragging && !isSuccess && !isFailed"><Right /></el-icon>
          <el-icon class="slider-icon" v-else-if="isSuccess"><CircleCheck /></el-icon>
          <el-icon class="slider-icon" v-else-if="isFailed"><WarningFilled /></el-icon>
          <el-icon class="slider-icon" v-else><DCaret /></el-icon>
        </div>
        <div class="slider-tip" :class="{ 'is-hidden': isDragging || isSuccess || isFailed }">
          向右拖动滑块，将拼图对齐到缺口处
        </div>
      </div>
      
      <div class="verify-actions">
        <el-button
          class="refresh-btn"
          @click="resetPuzzle"
          :disabled="isDragging"
          type="default"
          icon="Refresh"
          circle
          text
        ></el-button>
        <el-button
          class="close-btn"
          @click="handleCancel"
          type="primary"
          text
        >{{ isSuccess ? '确认' : '取消' }}</el-button>
      </div>
    </div>
  </el-dialog>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
import { 
  Lock, 
  Right, 
  DCaret, 
  CircleCheck, 
  Warning, 
  WarningFilled, 
  Refresh, 
  Close 
} from '@element-plus/icons-vue';

// Props
const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  }
});

// Emits
const emit = defineEmits(['update:visible', 'success', 'cancel']);

// Refs
const puzzleEl = ref(null);
const puzzleBg = ref(null);
const sliderBtn = ref(null);

// State
const dialogVisible = ref(false);
const puzzleWidth = ref(0);
const puzzleHeight = ref(0);
const gapSize = ref(40); // 缺口大小
const gapLeft = ref(0);
const gapTop = ref(0);
const pieceLeft = ref(0);
const sliderWidth = ref(0);
const isDragging = ref(false);
const isSuccess = ref(false);
const isFailed = ref(false);
const startX = ref(0);
const tolerance = ref(5); // 允许误差

// 生成随机颜色
const getRandomColor = () => {
  const hue = Math.floor(Math.random() * 360);
  return `hsl(${hue}, 70%, 80%)`;
};

// 随机生成图案颜色
const bgColor = ref(getRandomColor());
const patternColors = ref([]);

// 生成随机图案
const generatePatternColors = () => {
  const colors = [];
  for (let i = 0; i < 12; i++) {
    colors.push(getRandomColor());
  }
  return colors;
};

// 生成随机图案样式
const bgPatternStyle = computed(() => {
  if (patternColors.value.length < 12) return '';
  
  // 创建一个随机的渐变背景
  const angle = Math.floor(Math.random() * 360);
  return `linear-gradient(${angle}deg, ${bgColor.value} 0%, 
          ${patternColors.value[0]} 20%, 
          ${patternColors.value[1]} 40%, 
          ${patternColors.value[2]} 60%, 
          ${patternColors.value[3]} 80%, 
          ${patternColors.value[4]} 100%)`;
});

// 生成切片图案样式
const piecePatternStyle = computed(() => {
  if (patternColors.value.length < 12) return '';
  
  // 创建与背景匹配的渐变，但稍微调整
  const angle = Math.floor(Math.random() * 360);
  return `linear-gradient(${angle}deg, ${bgColor.value} 0%, 
          ${patternColors.value[5]} 20%, 
          ${patternColors.value[6]} 40%, 
          ${patternColors.value[7]} 60%, 
          ${patternColors.value[8]} 80%, 
          ${patternColors.value[9]} 100%)`;
});

// 监听visible属性变化
const handleVisibleChange = (val) => {
  dialogVisible.value = val;
  if (val) {
    nextTick(() => {
      initPuzzle();
    });
  } else {
    resetState();
  }
};

// 计算随机位置，但确保它位于可见区域的右半部分
const getRandomPosition = () => {
  // 确保缺口在右半部分，让验证更明确
  const minLeft = puzzleWidth.value * 0.5; 
  const maxLeft = puzzleWidth.value - gapSize.value - 20;
  
  // 确保缺口有足够空间
  const tempGapLeft = Math.floor(Math.random() * (maxLeft - minLeft)) + minLeft;
  const tempGapTop = Math.floor(Math.random() * (puzzleHeight.value - gapSize.value - 40)) + 20;
  
  return { left: tempGapLeft, top: tempGapTop };
};

// 初始化拼图
const initPuzzle = () => {
  nextTick(() => {
    if (puzzleBg.value) {
      // 生成新的颜色方案
      bgColor.value = getRandomColor();
      patternColors.value = generatePatternColors();
      
      // 计算尺寸
      const rect = puzzleBg.value.getBoundingClientRect();
      puzzleWidth.value = rect.width;
      puzzleHeight.value = rect.height;
      
      // 先设置初始位置，避免出现undefined
      gapLeft.value = puzzleWidth.value * 0.7;
      gapTop.value = puzzleHeight.value * 0.5;
      
      // 稍微延迟确保DOM已经更新
      setTimeout(() => {
        const { left, top } = getRandomPosition();
        gapLeft.value = left;
        gapTop.value = top;
        
        resetSlider();
      }, 100);
    }
  });
};

// 重置滑块位置
const resetSlider = () => {
  pieceLeft.value = 0;
  sliderWidth.value = 0;
};

// 重置整个拼图
const resetPuzzle = () => {
  isSuccess.value = false;
  isFailed.value = false;
  isDragging.value = false;
  
  // 重新生成颜色方案
  bgColor.value = getRandomColor();
  patternColors.value = generatePatternColors();
  
  // 重新计算位置
  const { left, top } = getRandomPosition();
  gapLeft.value = left;
  gapTop.value = top;
  
  resetSlider();
};

// 重置所有状态
const resetState = () => {
  resetSlider();
  isSuccess.value = false;
  isFailed.value = false;
  isDragging.value = false;
};

// 滑块按下事件
const handleSliderDown = (e) => {
  if (isSuccess.value || isFailed.value) return;
  
  e.preventDefault();
  isDragging.value = true;
  startX.value = e.type === 'touchstart' ? e.touches[0].clientX : e.clientX;
  
  document.addEventListener('mousemove', handleSliderMove);
  document.addEventListener('touchmove', handleSliderMove);
  document.addEventListener('mouseup', handleSliderUp);
  document.addEventListener('touchend', handleSliderUp);
};

// 滑块移动事件
const handleSliderMove = (e) => {
  if (!isDragging.value) return;
  
  const clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
  let moveX = clientX - startX.value;
  
  // 限制滑块和拼图在容器内
  const maxMoveX = puzzleWidth.value - gapSize.value;
  moveX = Math.max(0, Math.min(moveX, maxMoveX));
  
  sliderWidth.value = moveX;
  pieceLeft.value = moveX;
};

// 滑块释放事件
const handleSliderUp = () => {
  if (!isDragging.value) return;
  
  document.removeEventListener('mousemove', handleSliderMove);
  document.removeEventListener('touchmove', handleSliderMove);
  document.removeEventListener('mouseup', handleSliderUp);
  document.removeEventListener('touchend', handleSliderUp);
  
  verifyResult();
};

// 验证结果
const verifyResult = () => {
  // 计算拼图与缺口的距离
  const distance = Math.abs(pieceLeft.value - gapLeft.value);
  
  if (distance <= tolerance.value) {
    // 验证成功
    isSuccess.value = true;
    isDragging.value = false;
    
    // 延迟发送成功事件和关闭对话框
    setTimeout(() => {
      emit('success');
      
      // 额外延迟关闭对话框，让用户看到成功状态
      setTimeout(() => {
        dialogVisible.value = false;
        emit('update:visible', false);
      }, 800);
    }, 300);
  } else {
    // 验证失败，显示失败状态
    isFailed.value = true;
    isDragging.value = false;
    
    // 延迟重置
    setTimeout(() => {
      resetPuzzle();
    }, 1000);
  }
};

// 取消验证
const handleCancel = () => {
  if (isSuccess.value) {
    emit('success');
  } else {
    emit('cancel');
  }
  dialogVisible.value = false;
  emit('update:visible', false);
};

// 初始化颜色
patternColors.value = generatePatternColors();

// 监听props变化
watch(() => props.visible, handleVisibleChange, { immediate: true });

// 组件卸载时清理事件监听
onBeforeUnmount(() => {
  document.removeEventListener('mousemove', handleSliderMove);
  document.removeEventListener('touchmove', handleSliderMove);
  document.removeEventListener('mouseup', handleSliderUp);
  document.removeEventListener('touchend', handleSliderUp);
});
</script>

<style lang="scss" scoped>
.verify-dialog {
  :deep(.el-dialog__header) {
    @apply hidden;
  }
  
  :deep(.el-dialog__body) {
    @apply p-0;
  }
  
  .verify-container {
    @apply rounded-lg overflow-hidden flex flex-col;
    
    .verify-header {
      @apply p-5 border-b border-gray-100 dark:border-gray-800;
      
      .verify-title {
        @apply flex items-center gap-2 mb-2;
        
        .title-icon {
          @apply w-8 h-8 rounded-full bg-blue-50 dark:bg-blue-900/30 
                 flex items-center justify-center text-blue-500 dark:text-blue-400;
          
          .el-icon {
            @apply text-lg;
          }
        }
        
        .title-text {
          @apply text-lg font-medium text-gray-800 dark:text-gray-200;
        }
      }
      
      .verify-desc {
        @apply text-sm text-gray-500 dark:text-gray-400 ml-10;
      }
    }
    
    .verify-puzzle {
      @apply relative bg-gray-50 dark:bg-gray-900 overflow-hidden;
      height: 180px;
      
      .puzzle-bg {
        @apply w-full h-full relative overflow-hidden;
        
        .puzzle-pattern {
          @apply w-full h-full;
        }
        
        .puzzle-gap {
          @apply absolute rounded-md border-2 border-white shadow-inner;
          width: 40px;
          height: 40px;
          box-shadow: 0 0 10px rgba(255,255,255,0.6) inset;
          
          // 添加动画效果，让缺口更明显
          animation: pulse 2s infinite;
          
          @keyframes pulse {
            0% { box-shadow: 0 0 10px rgba(255,255,255,0.6) inset; }
            50% { box-shadow: 0 0 15px rgba(255,255,255,0.9) inset; }
            100% { box-shadow: 0 0 10px rgba(255,255,255,0.6) inset; }
          }
        }
      }
      
      .puzzle-piece {
        @apply absolute rounded-md shadow-lg cursor-pointer transition-colors duration-200;
        width: 40px;
        height: 40px;
        overflow: hidden;
        
        .piece-content {
          @apply w-full h-full;
        }
        
        &.active {
          @apply ring-2 ring-blue-400 ring-offset-1;
          transform: scale(1.05);
        }
        
        &.success {
          @apply ring-2 ring-green-400 ring-offset-1;
        }
        
        &.fail {
          @apply ring-2 ring-red-400 ring-offset-1;
        }
      }
      
      .verify-result {
        @apply absolute inset-0 flex flex-col items-center justify-center bg-black/50 z-10;
        
        .result-icon {
          @apply text-4xl mb-3;
          
          &.success {
            @apply text-green-400;
          }
          
          &.fail {
            @apply text-red-400;
          }
        }
        
        .result-text {
          @apply text-lg font-medium;
          
          &.success {
            @apply text-green-200;
          }
          
          &.fail {
            @apply text-red-200;
          }
        }
      }
    }
    
    .verify-slider {
      @apply p-4 pb-3 relative;
      
      .slider-track {
        @apply h-12 bg-gray-100 dark:bg-gray-800 rounded-full relative overflow-hidden;
        
        .slider-track-inner {
          @apply h-full bg-blue-50 dark:bg-blue-900/30 transition-all duration-100;
        }
      }
      
      .slider-button {
        @apply absolute top-1/2 -translate-y-1/2 w-12 h-12 
               bg-white dark:bg-gray-700 rounded-full shadow-md
               flex items-center justify-center cursor-pointer
               transition-all duration-100;
        
        .slider-icon {
          @apply text-xl transition-transform duration-300;
        }
        
        &.active {
          @apply shadow-lg bg-blue-100 dark:bg-blue-900/70 text-blue-500 dark:text-blue-400;
          
          .slider-icon {
            transform: rotate(90deg);
          }
        }
        
        &.success {
          @apply bg-green-500 dark:bg-green-600 text-white shadow-green-200 dark:shadow-green-900;
        }
        
        &.fail {
          @apply bg-red-500 dark:bg-red-600 text-white shadow-red-200 dark:shadow-red-900;
        }
      }
      
      .slider-tip {
        @apply absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2
               text-sm text-gray-400 dark:text-gray-500 whitespace-nowrap
               pointer-events-none transition-opacity duration-300;
        
        &.is-hidden {
          @apply opacity-0;
        }
      }
    }
    
    .verify-actions {
      @apply flex justify-between items-center px-4 py-3 border-t border-gray-100 dark:border-gray-800;
      
      .refresh-btn {
        @apply text-gray-500 dark:text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 p-2;
      }
      
      .close-btn {
        @apply text-blue-500 dark:text-blue-400 font-medium;
      }
    }
  }
}
</style>
